-- Author:		Sorcerer Merlin
-- Date:		2012-06-30 @ 23:00 hrs

-- Desc:		For additional information
--              please contact me on Curse/CurseForge.com.

-- Setup the Addon Namespace and embed the ACE libraries we need into it
local AddonName, SMQ = ...;
LibStub("AceEvent-3.0"):Embed(SMQ);
LibStub("AceTimer-3.0"):Embed(SMQ);
local Console = LibStub("AceConsole-3.0");
local _G = _G; -- still not exactly sure how this helps, but grdn told me to use it LOL

-- Queue status variables, borrowed from iQueue
local STATUS_NONE = 0; -- set if queue isn't active
local STATUS_PAUSED = 1; -- WG/TB: Queue available, all others: paused
local STATUS_QUEUED = 2; -- set if queued
local STATUS_PROPOSAL = 3; -- set if invite is pending
local STATUS_ACTIVE = 4; -- set if in assembled group
-- colors
local COLOR_RED  = "|cffff0000";
local COLOR_GREEN= "|cff00ff00";
local COLOR_YELLOW= "|cffffff00";
local COLOR_CYAN = "|cff00ffff";
local COLOR_MAGENTA = "|cffff00ff";

local QUEUE_LFG 		= _G.LE_LFG_CATEGORY_LFD; -- ID for lfg dungeons used by Blizzard
local QUEUE_RF  		= _G.LE_LFG_CATEGORY_RF; -- ID for raid finder used by Blizzard
local QUEUE_SCE 		= _G.LE_LFG_CATEGORY_SCENARIO; -- ID for scenarios used by Blizzard
local QUEUE_LFR 		= _G.LE_LFG_CATEGORY_LFR; -- ID for LFR used by Blizzard
local QUEUE_PET			= _G.NUM_LE_LFG_CATEGORYS +1; -- virtual queue ID for pet battles
local QUEUE_PVP 		= _G.NUM_LE_LFG_CATEGORYS +2; -- virtual queue ID for PvP queues, set by me (should be 5)
local QUEUE_WG			= QUEUE_PVP +1; -- queue ID for Wintergrasp (should be 6)
local QUEUE_TB			= QUEUE_PVP +2; -- queue ID for Tol Barad (should be 7)

local Queues = { -- Stores a status for each queue category, defaults to STATUS_NONE
	[QUEUE_LFG] = STATUS_NONE,
	[QUEUE_RF]  = STATUS_NONE,
	[QUEUE_SCE] = STATUS_NONE,
	[QUEUE_LFR] = STATUS_NONE,
	[QUEUE_PET] = STATUS_NONE,
	[QUEUE_PVP] = STATUS_NONE,
	[QUEUE_WG]  = STATUS_NONE,
	[QUEUE_TB]	= STATUS_NONE,
};
-- End Queue Status Variables

-- Other random global variables
local nameMarkedTank = nil;
local modeEnterInstance = false;
local modeLeavingParty = false;
local lootMaxID = 0;
-- End other random crap

local function get_queue_name(queue,long)
	-- simply gets an abbreviation for the queue (e.g. Looking for Dungeon = LFG)
	if    ( queue == QUEUE_LFG ) then 
		if (long) then
			return "Dungeon Finder";
		else
			return "DF";
		end
	elseif( queue == QUEUE_RF  ) then 
		if (long) then
			return "Raid Finder";
		else
			return "RF";
		end
	elseif( queue == QUEUE_SCE ) then 
		if (long) then
			return "Scenario";
		else
			return "SCE";
		end
	elseif( queue == QUEUE_LFR ) then 
		return "LFR" -- we don't want to use this one, because I can't figure out how to handle it
	elseif( queue == QUEUE_PET ) then 
		if (long) then
			return "Pet Battles";
		else
			return "PET";
		end
	elseif( queue == QUEUE_PVP ) then 
		if (long) then
			return "Player V. Player";
		else
			return "PVP";
		end
	else
		return _G.UNKNOWN; -- should NEVER happen!
	end
end

-- Setup the LDB portion of the AddOn
SMQ.ldb = LibStub("LibDataBroker-1.1"):NewDataObject(AddonName, {
	type = "data source",
	text = "SMQ",
	icon = "Interface\\Addons\\SMQueue\\Icons\\EyeBall",
});

SMQ.ldb.ChangeIcon = function()
	local engFaction, _ = _G.UnitFactionGroup("player");
	local iconPVP = "Interface\\pvpframe\\pvp-currency-" .. strlower(engFaction);
	local iconPVE = "Interface\\Addons\\SMQueue\\Icons\\EyeBall";
	local iconPET = "Interface\\Icons\\ability_hunter_pet_turtle";
	local iconSCE = "Interface\\Icons\\achievement_zone_jadeforest";
	
	--if( not SMQ:IsQueued() ) then
		-- we are not queued, we should have 'SMQ' text and basic eye icon
		--SMQ.ldb.icon = iconPVE;
	--else
		-- Find the actual icon that we want to display
		if (SMQ.db.SelectedLDBQueue > 0 and SMQ.db.SelectedLDBQueue <= 3) then
			-- we are in a PvE queue
			SMQ.ldb.icon = iconPVE;
		elseif (SMQ.db.SelectedLDBQueue == QUEUE_SCE) then
			-- we are in a Scenario queue
			SMQ.ldb.icon = iconSCE;
		elseif (SMQ.db.SelectedLDBQueue == QUEUE_PET) then
			-- we are in a Pet Battles queue
			SMQ.ldb.icon = iconPET;
		elseif (SMQ.db.SelectedLDBQueue == QUEUE_PVP) then
			-- we are in a PVP Queue
			SMQ.ldb.icon = iconPVP;
		end
	--end
end

function SMQ:NextActiveQueue()
	while (Queues[self.db.SelectedLDBQueue] == STATUS_NONE) do
		SMQ.db.SelectedLDBQueue = SMQ.db.SelectedLDBQueue + 1;
		if (SMQ.db.SelectedLDBQueue == 2) then -- we are skipping the Looking for Raid one because it doesn't seem to work
			SMQ.db.SelectedLDBQueue = 3;
		end
		if (SMQ.db.SelectedLDBQueue > 6) then 
			SMQ.db.SelectedLDBQueue = 1;
		end		
	end
end

SMQ.ldb.OnClick = function(anchor, button)
	-- left click (no mod):    cycle thru available queues
	-- shift+left click:       toggle the PvE queue frame
	-- right click (no mod):   toggle the minimap icon menu
	-- shift+right click:      toggle the PvP queue frame
	if( button == "LeftButton" ) then
		-- on CTRL/ALT/Shift pressed
		if( _G.IsModifierKeyDown() ) then
			-- Shift + Left opens LFD frame
			if( _G.IsShiftKeyDown() ) then
				_G.ToggleLFDParentFrame();
			end
		else
			-- First we are loop thru the queues
			SMQ.db.SelectedLDBQueue = SMQ.db.SelectedLDBQueue + 1;
			if (SMQ.db.SelectedLDBQueue == 2) then -- we are skipping the Looking for Raid one because it doesn't seem to work
				SMQ.db.SelectedLDBQueue = 3;
			end
			if (SMQ.db.SelectedLDBQueue > 6) then 
				SMQ.db.SelectedLDBQueue = 1;
			end
			
			-- Bad hack to cover click-cycling queues when one exists, and auto-select is on
			--if (SMQ.db.AutoSelect == true) and (SMQ:HowManyQueued() > 1) then
			if (SMQ:HowManyQueued() > 1) then
				SMQ:NextActiveQueue();
				SMQ:Print(get_queue_name(SMQ.db.SelectedLDBQueue,true).." time now displaying on LDB.");
			end
		end
	-- right click
	elseif( button == "RightButton" ) then
		-- on CTRL/ALT/Shift pressed
		if( _G.IsModifierKeyDown() ) then
			-- Shift + Right opens PVP frame
			if( _G.IsShiftKeyDown() ) then
				_G.TogglePVPFrame();
			end
		else
			if( not SMQ:IsQueued() ) then
				return;
			end
			
			SMQ.ldb.OnLeave(anchor); -- hides the mouseover tooltip
			_G.QueueStatusDropDown_Show(_G.QueueStatusMinimapButton.DropDown, anchor:GetName()); -- shows Blizzard tooltip for leaving instead
			
			if( not _G["DropDownList1"]:IsVisible() ) then
				SMQ.ldb.OnEnter(anchor); -- re-shows the mouseover tooltip and hides Blizzard tooltip if clicked again
			end
		end
	end
end

SMQ.ldb.OnTooltipShow = function()
	local PvPQueued = false;

	-- Begin the tooltip with our info
	_G.GameTooltip:AddLine(COLOR_GREEN .. "SMQueue ".. COLOR_CYAN .. "v. " .. _G.GetAddOnMetadata("SMQueue", "Version") .."|r");
	_G.GameTooltip:AddLine(" "); -- blank line
	
	-- Check to see if we are queued or not to display the right tooltip
	if ( not SMQ:IsQueued() ) then
		_G.GameTooltip:AddLine(COLOR_RED .. "[Not in any queue]|r");
		_G.GameTooltip:AddLine(" "); -- blank line
		_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "Left Click ", COLOR_CYAN .. "Cycle thru displayed queue.|r");
		--_G.GameTooltip:AddLine(" "); -- blank line
		_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "Shift+Left Click ", COLOR_CYAN .. "Toggle PvE queue frame.|r");
		--_G.GameTooltip:AddLine(" "); -- blank line
		_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "Right Click ", COLOR_CYAN .. "Display queue menu.|r");
		--_G.GameTooltip:AddLine(" "); -- blank line
		_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "Shift+Right Click ", COLOR_CYAN .. "Toggle the PvP frame.|r");
		--_G.GameTooltip:AddLine(" "); -- blank line
		_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "/smq ", COLOR_CYAN .. "Shows the options dialog.|r");
	else
		-- this is where we display the tooltip we create instead of the built in one
		for i = 1, 6 do
			if (Queues[i] ~= STATUS_NONE) then
				-- Grab the name of the queue
				local QName = get_queue_name(i,true);
				
				-- We only wanna add a separator if it's after the first line
				if (i ~= 1) then _G.GameTooltip:AddLine(" "); end 
				
				-- Now let's pop through the queues and print out the info
				if (i <= 4) then
					local _;
					local hasData, _, tankNeed, healNeed, dpsNeed, tankTotal, healTotal, dpsTotal, _, _, instanceName, _, _, _, _, myWait, queuedTime = _G.GetLFGQueueStats(i);
					if (instanceName == nil) then instanceName = COLOR_MAGENTA .. "Unknown"; end
					if (hasData) then 
						_G.GameTooltip:AddLine(COLOR_GREEN .. QName .."|r");
						_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Name:", COLOR_CYAN .. instanceName .. "|r");
						_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Wait:", COLOR_CYAN .. formatTime(_G.GetTime() - queuedTime) .. "/" .. formatTime(myWait) .. "|r");
						
						-- Calcualte the other stuff
						tankCurrent = tankTotal - tankNeed;
						dpsCurrent = dpsTotal - dpsNeed;
						healCurrent = healTotal - healNeed;
						if (i <= 3) then -- we are not in a scenario
							-- Tank info
							if (tankNeed == 0) then -- we don't need anymore tanks
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Tanks:", COLOR_GREEN .. tankCurrent .. "/" .. tankTotal .. "|r");
							else -- we are still waiting on them
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Tanks:", COLOR_RED .. tankCurrent .. "/" .. tankTotal .. "|r");
							end
							-- DPS info
							if (dpsNeed == 0) then -- we don't need anymore dpss
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - DPS:", COLOR_GREEN .. dpsCurrent .. "/" .. dpsTotal .. "|r");
							else -- we are still waiting on them
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - DPS:", COLOR_RED .. dpsCurrent .. "/" .. dpsTotal .. "|r");
							end
							-- Heal info
							if (healNeed == 0) then -- we don't need anymore heals
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Heals:", COLOR_GREEN .. healCurrent .. "/" .. healTotal .. "|r");
							else -- we are still waiting on them
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Heals:", COLOR_RED .. healCurrent .. "/" .. healTotal .. "|r");
							end
						else
							-- DPS info
							if (dpsNeed == 0) then -- we don't need anymore dpss
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Players:", COLOR_GREEN .. dpsCurrent .. "/" .. dpsTotal .. "|r");
							else -- we are still waiting on them
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Players:", COLOR_RED .. dpsCurrent .. "/" .. dpsTotal .. "|r");
							end
						end
					else
						_G.GameTooltip:AddLine(COLOR_GREEN .. QName .."|r");
						_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Name:", COLOR_CYAN .. instanceName .. "|r");
						_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Wait:", COLOR_CYAN .. " [...]|r");
					end
				elseif (i == 5) then
					-- now the Pet Queues, which for now is disabled until xpac is released, then we can code some more! :D
					_G.GameTooltip:AddLine(COLOR_RED.."Pet Battles|r");
				elseif (i == 6) then
					-- Now we should be on to PvP queues
					for i = 1, _G.GetMaxBattlefieldID() do
					--local status, mapName, instanceID, levelRangeMin, levelRangeMax, teamSize, registeredMatch, eligibleInQueue, waitingOnOtherActivity = GetBattlefieldStatus(i);
						local status, mapName = _G.GetBattlefieldStatus(i);
						if (status == "queued") then
							PvPQueued = true;
							local bgTime = 9999999;
							if (_G.GetBattlefieldEstimatedWaitTime(i) - _G.GetBattlefieldTimeWaited(i)) < bgTime then 
								bgTime = (_G.GetBattlefieldEstimatedWaitTime(i) - _G.GetBattlefieldTimeWaited(i));
								_G.GameTooltip:AddLine(COLOR_GREEN .. QName .."|r");
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Name:", COLOR_CYAN .. mapName .. "|r");
								_G.GameTooltip:AddDoubleLine(COLOR_YELLOW .. "   - Wait:", COLOR_CYAN .. formatTime(_G.GetBattlefieldTimeWaited(i) / 1000) .. "/" .. formatTime(_G.GetBattlefieldEstimatedWaitTime(i) / 1000) .. "|r");
							end
						end
					end
				end
			end
		end
	end
end

SMQ.ldb.OnEnter = function(anchor)
	-- does not show mouseover tooltip when not queued (or just available queue) or if Blizzard tooltip is visible
	local queued, paused = SMQ:IsQueued();

	-- don't display anything if the drop down list (menu option) is down
	if( _G["DropDownList1"]:IsVisible() ) then
		return;
	end
	
	if( not SMQ:IsQueued() ) then
		-- not queued, so we can display our default tooltip for help purposes, version info, etc.
		_G.GameTooltip:SetOwner(anchor, "ANCHOR_NONE");
		_G.GameTooltip:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT");
		_G.GameTooltip:ClearLines();
		SMQ.ldb.OnTooltipShow(GameTooltip);
		_G.GameTooltip:Show();
	else		
		if (SMQ.db.ShowBuiltIn) then
			-- We are queued, so we are going to hook the minimap button tooltip
			_G.GameTooltip:Hide();
			
			-- the mouse over tooltip (Blizzard UI element) needs to be attached to Broker plugin
			if( _G.QueueStatusFrame:GetParent() ~= anchor ) then
				_G.QueueStatusFrame:ClearAllPoints();
				_G.QueueStatusFrame:SetParent(anchor);
				_G.QueueStatusFrame:SetClampedToScreen(true);
				_G.QueueStatusFrame:SetPoint("TOP", anchor, "TOP", 14, -anchor:GetHeight());
			end
			
			_G.QueueStatusFrame:Show();
		else
			-- Now we are going to show our tooltip
			_G.GameTooltip:SetOwner(anchor, "ANCHOR_NONE");
			_G.GameTooltip:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT");
			_G.GameTooltip:ClearLines();
			SMQ.ldb.OnTooltipShow(GameTooltip);
			_G.GameTooltip:Show();
		end
	end
end

SMQ.ldb.OnLeave = function(anchor)
	_G.QueueStatusFrame:Hide();
	_G.GameTooltip:Hide();
end
-- End Setup LDB

-- Timer crap
function SMQ:QueueTimer()
	self:UpdateBroker();
end
-- End Timer crap

-- Printing crap
function SMQ:Print(msg)
	Console:Print("|cffffd700[SMQueue]: |cffff8c00"..msg.."|r");
end
-- End Printing crap

-- Setup the INIT of the AddOn
function SMQ:Initialize()
	-- Print out the version info
	SMQ:Print("Version " ..  _G.GetAddOnMetadata("SMQueue", "Version") .. " initialized!");

	-- Hide the MiniMap Button for the Queues (assuming the option works! :D).
	_G.QueueStatusMinimapButton.Show = _G.QueueStatusMinimapButton.Hide;
	_G.QueueStatusMinimapButton:Hide();
	
	-- Load the database and configuration information
	self.db = LibStub("AceDB-3.0"):New("SMQueueDB", self:CreateDB(), "Default").profile;
	
	-- Register all of the Events that we need to watch
	-- All
	self:RegisterEvent("GROUP_ROSTER_UPDATE", "EventHandler"); -- when leaving a battlefield, no event is fired. So we check the group. Also used for new party text and marking tank.
	self:RegisterEvent("ZONE_CHANGED_NEW_AREA", "EventHandler"); -- need for loot rolling detection and world pvp areas
	self:RegisterEvent("ZONE_CHANGED", "EventHandler"); -- need for loot rolling detection and world pvp areas
	self:RegisterEvent("LFG_COMPLETION_REWARD", "EventHandler"); -- we need to track for leaveafterloot
	
	-- PvE
	self:RegisterEvent("LFG_UPDATE", "EventHandler");
	self:RegisterEvent("LFG_PROPOSAL_UPDATE", "EventHandler");
	self:RegisterEvent("LFG_PROPOSAL_FAILED", "EventHandler");
	self:RegisterEvent("LFG_PROPOSAL_SUCCEEDED", "EventHandler");
	self:RegisterEvent("LFG_PROPOSAL_SHOW", "EventHandler");
	self:RegisterEvent("LFG_QUEUE_STATUS_UPDATE", "EventHandler");
	
	-- PvP
	self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS", "EventHandler");
	
	-- Pet Battles
	self:RegisterEvent("PET_BATTLE_QUEUE_STATUS", "EventHandler");
	
	-- Setup the timer
	self:ScheduleRepeatingTimer("QueueTimer", 1);

end
SMQ:RegisterEvent("PLAYER_LOGIN", "Initialize");
-- End INIT

-- Returns the type of instance that we are inside of
function GetInstanceType(forChat)
	local _, instanceType, _, _, _, _, _ = _G.GetInstanceInfo();
	if (instanceType == nil) then -- apparently nil means scenario..?
		if (forChat == true) then
			instanceType = "party";
		else
			instanceType = "scenario";
		end
	end
	
	return string.upper(instanceType);
end

-- Event Handler
function SMQ:EventHandler(event,...)
	local mode, submode;

	--self:Print(event .. " event fired!");
	
	-- We have left the dungeon most likely, as the player has changed zones/maps, so cancel leaveafterloot
	-- if we have it setup.
	if event == "ZONE_CHANGED_NEW_AREA" then
		if modeLeavingParty then
			 self:UnregisterEvent("CHAT_MSG_LOOT")
			 modeLeavingParty = false;
			 self:Print("Zone Change! Cancelling Leave After Loot.");
		end
	end
	
	-- Check to see if we are entering the instance, etc., so we can display the party intro text if people want it
	if event == "LFG_PROPOSAL_SHOW" then
		-- First we need to set the marked tank to nada
		nameMarkedTank = nil;
		-- We also need to tell the addon we are about to enter the instance
		modeEnterInstance = true;
		-- Check to see if they want to sound the alarm
		if self.db.SoundAlarm then
			PlaySoundFile("Interface\\AddOns\\SMQueue\\Sounds\\QueueAlarm.mp3")
		end
		-- We need to flash the screen if the option is present
		if self.db.FlashScreen then
			FlashScreen();
		end
	end
	
	-- We have completed the dungeon/raid
	if event == "LFG_COMPLETION_REWARD" then
		-- Register the start loot event, since it doesn't need to be handled except when dealing
		-- with loot.
		if (GetInstanceType(false) == "SCENARIO") then
			-- If this option is set, then we need to send a fairwell to everyone
			if self.db.PartyGoodbye then
				_G.SendChatMessage(self.db.PartyGoodbyeText, GetInstanceType(true));
			end
			
			-- Let's see if they want to leave, if so, leave the group
			if self.db.LeaveAfterLoot then
				_G.StaticPopup_Show ("LEAVE_AFTER");
			end
		else
			self:RegisterEvent("START_LOOT_ROLL", "EventHandler")
		end
	end
	
	-- We are starting the loot rolling process. So we need to check for the end of the rolling process
	-- for leaving after loot, set the Leaving Party mode, and do a few other things.
	if event == "START_LOOT_ROLL" then
		local maxID, rollTime = ...
		lootMaxID = maxID;
		self:RegisterEvent("CHAT_MSG_LOOT", "EventHandler");
		modeLeavingParty = true;
	end
	
	-- Fires when loot is being rolled on and displayed in the chat channel. We will use this event to leave
	-- after loot (with prompt) and to say our fairwell (if we want to).
	if event == "CHAT_MSG_LOOT" then
		local lootInProgress = false
		for i = 1, lootMaxID do
			if _G.GetLootRollItemInfo(i) then
				lootInProgress = true
				break
			end
		end
		if lootInProgress == false then
			-- Unregister the events for now
			self:UnregisterEvent("CHAT_MSG_LOOT");
			self:UnregisterEvent("START_LOOT_ROLL");		
			
			-- If this option is set, then we need to send a fairwell to everyone
			if self.db.PartyGoodbye then
				_G.SendChatMessage(self.db.PartyGoodbyeText, GetInstanceType(true));
			end
			
			-- Let's see if they want to leave, if so, leave the group
			if self.db.LeaveAfterLoot then
				_G.StaticPopup_Show ("LEAVE_AFTER");
			end
			
			-- Reset the mode
			modeLeavingParty = false;
		end
	end
	
	-- We have the Party Members Changed event, meaning most likely someone who's joined/left our party
	if event == "GROUP_ROSTER_UPDATE" then
		if self.db.PartyIntro then
			-- We wanted to spit out some text when we first start the party/raid. So we are going to check
			-- and see if we just started the party/raid and output selected text to appropriate chat channel.
			if modeEnterInstance then
				_G.SendChatMessage(self.db.PartyIntroText, GetInstanceType(true));
				modeEnterInstance = false;
			end
		end
		if self.db.MarkTank then
			-- We need to mark the tank. First check to see if we are the tank, and mark us, then set the
			-- name of the player tank marked to our name. If not, loop through the other party members
			-- until we find the tank and mark them instead.
			if _G.UnitGroupRolesAssigned("player") == "TANK" then
				if nameMarkedTank ~= _G.UnitName("player") then
					_G.SetRaidTarget("player", 1);
					nameMarkedTank = _G.UnitName("player");
				end
			else
				for i = 1, 4 do
					if _G.UnitGroupRolesAssigned("party" .. i) == "TANK" then
						if nameMarkedTank ~= _G.UnitName("party" .. i) then
							_G.SetRaidTarget("party" .. i, 1);
							nameMarkedTank = _G.UnitName("party" .. i);
							break
						end
					end
				end
			end
		end
	end
	
	-- check PvE queues
	for i = 1, _G.NUM_LE_LFG_CATEGORYS do
		mode, submode = _G.GetLFGMode(i);
		
		if( not mode or mode == "abandonedInDungeon" ) then
			Queues[i] = STATUS_NONE;
			if( self["Queue"..i.."Current"] or self["Queue"..i.."Total"] ) then
				self["Queue"..i.."Current"] = nil;
				self["Queue"..i.."Total"] = nil;
			end
		elseif( mode == "suspended" ) then
			Queues[i] = STATUS_PAUSED;
		else			
			if( mode == "lfgparty" ) then
				Queues[i] = STATUS_ACTIVE;
			elseif( mode == "proposal" ) then
				Queues[i] = STATUS_PROPOSAL;
			elseif( mode == "queued" ) then
				Queues[i] = STATUS_QUEUED;
				--local _
				--local hasData, _, tankNeed, healNeed, dpsNeed, tankTotal, healTotal, dpsTotal = _G.GetLFGQueueStats(i);
				--local current, total;
				
				--if( hasData ) then
					--total = tankTotal + healTotal + dpsTotal;
					--current = total - (tankNeed + healNeed + dpsNeed);
					--self["Queue"..i.."Current"] = current - 1; -- we sub the player from the needs, because he is always marked as "found"
					--self["Queue"..i.."Total"] = total - 1; -- we sub the player from the totals, see comment above
				--end
			end
		end
	end
	
	-- check PvP queues
	
	-- There are one or two PvP queues available.
	-- 1 queue if queueing for random BGs, 2 queues if queueing for specified BGs
	-- We simply reset the PvP queue status and run our checks. This is a really clean way without declaring 1-2 helper vars.
	Queues[QUEUE_PVP] = STATUS_NONE;
	for i = 1, _G.GetMaxBattlefieldID() do
		--local status, mapName, instanceID, levelRangeMin, levelRangeMax, teamSize, registeredMatch, eligibleInQueue, waitingOnOtherActivity = GetBattlefieldStatus(i);
		local status = _G.GetBattlefieldStatus(i);
		
		if( status and status ~= "none" and status ~= "error" ) then
			if( status == "active" ) then
				status = STATUS_ACTIVE;
			elseif( status == "confirm" ) then
				status = STATUS_PROPOSAL;
			elseif( status == "queued" ) then
				status = STATUS_QUEUED;
			end
			
			-- Because of 2 queues possible and just 1 PvP display, we store the "higher" queue status
			Queues[QUEUE_PVP] = status > Queues[QUEUE_PVP] and status or Queues[QUEUE_PVP];
		end
	end
	
	-- check pet battles
	mode = _G.C_PetBattles.GetPVPMatchmakingInfo();
	if( mode == "queued" ) then
		Queues[QUEUE_PET] = STATUS_QUEUED;
	elseif( mode == "suspended" ) then
		Queues[QUEUE_PET] = STATUS_PAUSED;
	elseif( mode == "proposal" ) then
		Queues[QUEUE_PET] = STATUS_PROPOSAL;
	elseif( mode == "entry" ) then
		Queues[QUEUE_PET] = STATUS_ACTIVE;
	else
		Queues[QUEUE_PET] = STATUS_NONE
	end
	
	self:UpdateBroker(); -- display the crap we just discovered
end
-- END Event Handler

-- Update Broker

function SMQ:HowManyQueued()
	local totalQ = 0;
	
	-- figure out how many queues we are in right now, and return it.
	for i = 1,6 do
		if (Queues[i] ~= STATUS_NONE) then
			totalQ = totalQ + 1;
		end
	end
	
	-- return whatever we may have counted
	return totalQ;
end

function SMQ:GetSingleQueue()
	-- figure out how many queues we are in right now, and return it.
	for i = 1,6 do
		if (Queues[i] ~= STATUS_NONE) then
			return i;
		end
	end
	
	-- return nil if we get nothing
	return nil
end

function SMQ:IsQueued() -- returns 1 if queued somewhere (2 if just available queue), nil otherwise
	local answer, paused = false, false;
	
	for i, v in ipairs(Queues) do
		if( v > STATUS_PAUSED ) then
			answer = true;
		elseif( v == STATUS_PAUSED ) then
			paused = true;
		end
	end
	
	return answer, paused;
end

-- This function formats time
function formatTime(deltatime)
	if (deltatime >= 1) then
		output = string.format("%02d:%02d", math.floor(deltatime/60), deltatime-(math.floor(deltatime/60)*60))
	else
		-- if this happens, then we don't know what the time limit is
		output = COLOR_MAGENTA .. "??:??|r";
	end
	return(output);
end

function SMQ:GetQueuedText(selectDB)
-- Check the status of the selected Queue that they wish to display, and output text accordingly
	local SelStatus = Queues[selectDB];
	local QName = get_queue_name(selectDB,false);
	if (SelStatus == STATUS_NONE) then
		--if (self.db.AutoSelect) then
			-- If we have reach this point, we have no queues open, and auto-select is on
			-- Crappy hack! check to see if we are still queued and if so change the queue to active
			if (SMQ:HowManyQueued() > 1) then
				SMQ:NextActiveQueue();
			end
			self.ldb.icon = "Interface\\Addons\\SMQueue\\Icons\\EyeBall"; -- another crappy hack
			return(COLOR_GREEN .. "SMQ|r");
		--else
			-- Return the name of the queue we have selected
			--return(COLOR_RED .. QName .. "|r");
		--end
	elseif (SelStatus == STATUS_PAUSED) then
		return(COLOR_YELLOW .. QName .. COLOR_CYAN .. " [Paused]|r");
	elseif (SelStatus == STATUS_PROPOSAL) then
		return(COLOR_YELLOW .. QName .. COLOR_CYAN .. " [Proposal]|r");
	elseif (SelStatus == STATUS_ACTIVE) then
		return(COLOR_GREEN .. QName .. COLOR_CYAN .. " [Active]|r");
	elseif (SelStatus == STATUS_QUEUED) then
		-- check for our PvE queues first
		if (selectDB <= 4) then
			local _;
			local hasData, _, tankNeed, healNeed, dpsNeed, tankTotal, healTotal, dpsTotal, _, _, instanceName, _, _, _, _, myWait, queuedTime = _G.GetLFGQueueStats(self.db.SelectedLDBQueue);
		
			if (hasData) then 
				if (self.db.WaitTimeMode) then
					-- we are showing them the time waiting information
					return(COLOR_GREEN .. QName .. " " .. COLOR_CYAN .. formatTime(_G.GetTime() - queuedTime) .. "/" .. formatTime(myWait) .. "|r");
				else
					-- Calcualte the other stuff
					local txtLDB = "";
					tankCurrent = tankTotal - tankNeed;
					dpsCurrent = dpsTotal - dpsNeed;
					healCurrent = healTotal - healNeed;
					
					-- start the prefix
					txtLDB = txtLDB .. COLOR_CYAN .. QName .. "    ";
					-- we are showing them the roles filled info (THD) like SMToken
					
					-- TANKS
					if (tankCurrent == tankTotal) then
						-- we have all the tanks, so green T
						txtLDB = txtLDB .. COLOR_GREEN .. "T|r" .. COLOR_CYAN .. "/|r";
					else
						-- we don't have all the tanks, so red -#T
						txtLDB = txtLDB .. COLOR_RED .. "-" .. tostring(tankTotal - tankCurrent) .. "T|r" .. COLOR_CYAN .. "/|r";
					end
					
					-- HEALS
					if (healCurrent == healTotal) then
						-- we have all the heals, so green H
						txtLDB = txtLDB .. COLOR_GREEN .. "H|r" .. COLOR_CYAN .. "/|r";
					else
						-- we don't have all the tanks, so red -#H
						txtLDB = txtLDB .. COLOR_RED .. "-" .. tostring(healTotal - healCurrent) .. "H|r" .. COLOR_CYAN .. "/|r";
					end
					
					-- DPS
					if (dpsCurrent == dpsTotal) then
						-- we have all the DPS, so green D
						txtLDB = txtLDB .. COLOR_GREEN .. "D|r";
					else
						-- we don't have all the DPS, so red -#D
						txtLDB = txtLDB .. COLOR_RED .. "-" .. tostring(dpsTotal - dpsCurrent) .. "D|r";
					end
					
					-- Give it back to them
					return(txtLDB);
				end
			else
				-- no matter whether TimeWaitMode or not, there isn't data yet.
				return(COLOR_GREEN.. QName .. COLOR_CYAN .. " [...]|r");
			end
		elseif (selectDB == 5) then
			-- now the Pet Queues, which for now is disabled until xpac is released, then we can code some more! :D
			return(COLOR_RED .. "PET|r");
		elseif (selectDB == 6) then
			-- Now we should be on to PvP queues. As far as i know, we cannot do any type of THD or similar for PvP so TimeWaitMode is irrelevant.
			for i = 1, _G.GetMaxBattlefieldID() do
			--local status, mapName, instanceID, levelRangeMin, levelRangeMax, teamSize, registeredMatch, eligibleInQueue, waitingOnOtherActivity = GetBattlefieldStatus(i);
				local status = _G.GetBattlefieldStatus(i);
				if (status == "queued") then
					PvPQueued = true;
					local bgTime = 9999999;
					if (_G.GetBattlefieldEstimatedWaitTime(i) - _G.GetBattlefieldTimeWaited(i)) < bgTime then 
						bgTime = (_G.GetBattlefieldEstimatedWaitTime(i) - _G.GetBattlefieldTimeWaited(i));
						return(COLOR_GREEN .. QName .. " " .. COLOR_CYAN .. formatTime(_G.GetBattlefieldTimeWaited(i) / 1000) .. "/" .. formatTime(_G.GetBattlefieldEstimatedWaitTime(i) / 1000) .. "|r");
					end
				end
			end
			
			-- fix to make it red if we aren't in Q
			if (PvPQueued == false) then
				return(COLOR_RED .. "PVP|r");
			end
		end
	end
	
	-- If we got this far, there is a problem, so return NIL
	return nil;
end

function SMQ:UpdateBroker()
	local PvPQueued = false;
	
	-- Change the icon based on our currently selected queue
	self.ldb.ChangeIcon();
	
	-- Automatically switching displaying LDB text to the only Q we are in
	--if (self.db.AutoSelect) and (self:HowManyQueued() == 1) then
	if (self:HowManyQueued() == 1) then
		self.db.SelectedLDBQueue = self:GetSingleQueue();
	end
	-- end Auto select Q
	
	-- Set the queue text on the LDB
	self.ldb.text = self:GetQueuedText(self.db.SelectedLDBQueue);
end
-- END Update Broker

-- Static Leave DLG --
StaticPopupDialogs["LEAVE_AFTER"] = {
	text = "Loot rolls have finished, would you like to leave now?",
	button1 = "Yes",
	button2 = "No",
	OnAccept = function()
		_G.LeaveParty()
	end,
	timeout = 30,
	whileDead = true,
	hideOnEscape = true,
};
-- End Static Leave DLG --

------------- Flash Screen -------------
local SMQFlash = _G.CreateFrame("Frame")
local FlashFrame = nil
function FlashScreen()
	if not FlashFrame then
		local flasher = _G.CreateFrame("Frame", "SMQFlash")
		flasher:SetToplevel(true)
		flasher:SetFrameStrata("FULLSCREEN_DIALOG")
		flasher:SetAllPoints(UIParent)
		flasher:EnableMouse(false)
		flasher:Hide()
		flasher.texture = flasher:CreateTexture(nil, "BACKGROUND")
		flasher.texture:SetTexture("Interface\\FullScreenTextures\\LowHealth")
		flasher.texture:SetAllPoints(UIParent)
		flasher.texture:SetBlendMode("ADD")
		flasher:SetScript("OnShow", function(self)
			self.elapsed = 0
			self:SetAlpha(0)
		end)
		flasher:SetScript("OnUpdate", function(self, elapsed)
			elapsed = self.elapsed + elapsed
			if elapsed < 5 then
				local alpha = elapsed % 1.3
				if alpha < 0.15 then
					self:SetAlpha(alpha / 0.15)
				elseif alpha < 0.9 then
					self:SetAlpha(1 - (alpha - 0.15) / 0.6)
				else
					self:SetAlpha(0)
				end
			else
				self:Hide()
			end
			self.elapsed = elapsed
		end)
		FlashFrame = flasher
	end
	FlashFrame:Show()
end
------------- End Flash Screen ----------